package com.zzh.greendaotest.swipe;

import android.content.Context;
import android.graphics.Rect;
import android.support.v4.view.GestureDetectorCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;

public class MySwipeLayout extends ViewGroup {

    private static final String TAG = MySwipeLayout.class.getSimpleName();


    private GestureDetectorCompat mGestureDetectorCompat;
    private ViewDragHelper mViewDragHelper;

    private Context mContext;

    private View viewOne;
    private View viewTwo;
    private View viewMain;


    private Rect rectOneClose = new Rect();
    private Rect rectTwoClose = new Rect();
    private Rect rectMainClose = new Rect();
    private Rect rectOneOpen = new Rect();
    private Rect rectTwoOpen = new Rect();
    private Rect rectMainLeftOpen = new Rect();
    private Rect rectMainRightOpen = new Rect();

    private boolean isOpen = false;

    public MySwipeLayout(Context context) {
        this(context, null);
    }

    public MySwipeLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MySwipeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        this.mContext = context;
        mGestureDetectorCompat = new GestureDetectorCompat(mContext, onGestureListener);
        mViewDragHelper = ViewDragHelper.create(this, 1.0f, callback);
        mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_ALL);
    }

    private void initView() {
        if (getChildCount() < 3) {
            new Throwable("throw view count ").printStackTrace();
            return;
        }
        viewOne = getChildAt(0);
        viewTwo = getChildAt(1);
        viewMain = getChildAt(2);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        initView();
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {

        for (int i = 0; i < getChildCount(); i++) {
            View childView = getChildAt(i);

            final int minLeft = getPaddingLeft();
            final int maxRight = Math.max(r - getPaddingRight() - l, 0);
            final int minTop = getPaddingTop();
            final int maxBottom = Math.max(b - getPaddingBottom() - t, 0);

            int measuredChildHeight = childView.getMeasuredHeight();
            int measuredChildWidth = childView.getMeasuredWidth();

            // need to take account if child size is match_parent
            final LayoutParams childParams = childView.getLayoutParams();
            boolean matchParentHeight = false;
            boolean matchParentWidth = false;

            if (childParams != null) {
                matchParentHeight = (childParams.height == LayoutParams.MATCH_PARENT) ||
                        (childParams.height == LayoutParams.FILL_PARENT);
                matchParentWidth = (childParams.width == LayoutParams.MATCH_PARENT) ||
                        (childParams.width == LayoutParams.FILL_PARENT);
            }

            if (matchParentHeight) {
                measuredChildHeight = maxBottom - minTop;
                childParams.height = measuredChildHeight;
            }

            if (matchParentWidth) {
                measuredChildWidth = maxRight - minLeft;
                childParams.width = measuredChildWidth;
            }

            if (i == 0) {
                childView.layout(l - measuredChildWidth, getPaddingTop(), l, measuredChildHeight);
            } else if (i == 1) {
                childView.layout(r, getPaddingTop(), r + measuredChildWidth, measuredChildHeight);
            } else {
                childView.layout(l, getPaddingTop(), r, measuredChildHeight);
            }
        }
        initRects();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (getChildCount() < 3) {
            throw new RuntimeException("Layout must have two children");
        }

        final LayoutParams params = getLayoutParams();

        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        int desiredWidth = 0;
        int desiredHeight = 0;

        // first find the largest child
        for (int i = 0; i < getChildCount(); i++) {
            final View child = getChildAt(i);
            measureChild(child, widthMeasureSpec, heightMeasureSpec);
            desiredWidth = Math.max(child.getMeasuredWidth(), desiredWidth);
            desiredHeight = Math.max(child.getMeasuredHeight(), desiredHeight);
        }
        // create new measure spec using the largest child width
        widthMeasureSpec = MeasureSpec.makeMeasureSpec(desiredWidth, widthMode);
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(desiredHeight, heightMode);

        final int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
        final int measuredHeight = MeasureSpec.getSize(heightMeasureSpec);

        for (int i = 0; i < getChildCount(); i++) {
            final View child = getChildAt(i);
            final LayoutParams childParams = child.getLayoutParams();

            if (childParams != null) {
                if (childParams.height == LayoutParams.MATCH_PARENT) {
                    child.setMinimumHeight(measuredHeight);
                }

                if (childParams.width == LayoutParams.MATCH_PARENT) {
                    child.setMinimumWidth(measuredWidth);
                }
            }

            measureChild(child, widthMeasureSpec, heightMeasureSpec);
            desiredWidth = Math.max(child.getMeasuredWidth(), desiredWidth);
            desiredHeight = Math.max(child.getMeasuredHeight(), desiredHeight);
        }

        // taking accounts of padding
        desiredWidth += getPaddingLeft() + getPaddingRight();
        desiredHeight += getPaddingTop() + getPaddingBottom();

        // adjust desired width
        if (widthMode == MeasureSpec.EXACTLY) {
            desiredWidth = measuredWidth;
        } else {
            if (params.width == LayoutParams.MATCH_PARENT) {
                desiredWidth = measuredWidth;
            }

            if (widthMode == MeasureSpec.AT_MOST) {
                desiredWidth = (desiredWidth > measuredWidth) ? measuredWidth : desiredWidth;
            }
        }

        // adjust desired height
        if (heightMode == MeasureSpec.EXACTLY) {
            desiredHeight = measuredHeight;
        } else {
            if (params.height == LayoutParams.MATCH_PARENT) {
                desiredHeight = measuredHeight;
            }

            if (heightMode == MeasureSpec.AT_MOST) {
                desiredHeight = (desiredHeight > measuredHeight) ? measuredHeight : desiredHeight;
            }
        }

        setMeasuredDimension(desiredWidth, desiredHeight);
    }

    private void initRects() {
        rectMainClose.set(viewMain.getLeft(), viewMain.getTop(), viewMain.getRight(), viewMain.getBottom());
        rectOneClose.set(viewOne.getLeft(), viewOne.getTop(), viewOne.getRight(), viewOne.getBottom());
        rectTwoClose.set(viewTwo.getLeft(), viewTwo.getTop(), viewTwo.getRight(), viewTwo.getBottom());

        rectMainLeftOpen.set(viewMain.getLeft() + viewOne.getWidth(), viewMain.getTop(), viewMain.getRight() + viewOne.getWidth(), viewMain.getBottom());
        rectMainRightOpen.set(viewMain.getLeft() - viewTwo.getWidth(), viewMain.getTop(), viewMain.getRight() - viewTwo.getWidth(), viewMain.getBottom());

        rectOneOpen.set(viewOne.getLeft() + viewOne.getWidth(), viewOne.getTop(), viewOne.getRight() + viewOne.getWidth(), viewOne.getBottom());
        rectTwoOpen.set(viewTwo.getLeft() - viewTwo.getWidth(), viewTwo.getTop(), viewTwo.getRight() - viewTwo.getWidth(), viewTwo.getBottom());
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mGestureDetectorCompat.onTouchEvent(event);
        mViewDragHelper.processTouchEvent(event);
        return true;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return true;
    }

    private GestureDetector.OnGestureListener onGestureListener = new GestureDetector.OnGestureListener() {

        int touchSiop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
        boolean hasDisallowed = false;
        boolean isCalculate = true;

        @Override
        public boolean onDown(MotionEvent e) {
            hasDisallowed = false;
            isCalculate = true;
            return true;
        }

        @Override
        public void onShowPress(MotionEvent e) {

        }

        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            return true;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            if (isCalculate) {
                if (Math.abs(e1.getX() - e2.getX()) > touchSiop) {
                    isCalculate = false;
                    hasDisallowed = true;
                } else if (Math.abs(e1.getY() - e2.getY()) > touchSiop){
                    isCalculate = false;
                    hasDisallowed = false;
                }
            }
            getParent().requestDisallowInterceptTouchEvent(hasDisallowed);
            return false;
        }

        @Override
        public void onLongPress(MotionEvent e) {

        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            return false;
        }
    };

    private boolean isOpenLeft;
    private boolean isOPenRight;

    private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return child == viewMain ? true : false;
        }

        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            if (child.getLeft() >= viewOne.getWidth() && dx > 0) {
                return viewOne.getWidth();
            }
            if (child.getLeft() <= -viewTwo.getWidth() && dx < 0) {
                return -viewTwo.getWidth();
            }
            return left;
        }

        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            if (releasedChild.getLeft() > 0) {
                // 左划
                isOpenLeft = releasedChild.getLeft() > viewOne.getWidth() / 2 ? true : false;
                isOPenRight = false;
            } else if (releasedChild.getLeft() < 0) {
                // 右划
                isOPenRight = -releasedChild.getLeft() > viewTwo.getWidth() / 2 ? true : false;
                isOpenLeft = false;
            } else {
                isOPenRight = false;
                isOpenLeft = false;
            }
            if (isOpenLeft) {
                open(true, 1);
            } else if (isOPenRight) {
                open(true, 2);
            } else {
                close(true);
            }
        }

        @Override
        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
            super.onViewPositionChanged(changedView, left, top, dx, dy);
            viewOne.layout(rectOneClose.left + left, rectOneClose.top, rectOneClose.right + left, rectOneClose.bottom);
            viewTwo.layout(rectTwoClose.left + left, rectTwoClose.top, rectTwoClose.right + left, rectTwoClose.bottom);
        }
    };


    private void open(boolean animation, int leftOrRight) {
        isOpen = true;
        if (animation) {
            if (leftOrRight == 1) {
                mViewDragHelper.smoothSlideViewTo(viewMain, rectMainLeftOpen.left, rectMainLeftOpen.top);
            } else if (leftOrRight == 2) {
                mViewDragHelper.smoothSlideViewTo(viewMain, rectMainRightOpen.left, rectMainRightOpen.top);
            } else {
                viewMain.layout(rectMainClose.left, rectMainClose.top, rectMainClose.right, rectMainClose.bottom);
                viewOne.layout(rectOneClose.left, rectOneClose.top, rectOneClose.right, rectOneClose.bottom);
                viewTwo.layout(rectTwoClose.left, rectTwoClose.top, rectTwoClose.right, rectTwoClose.bottom);
            }

        } else {
            mViewDragHelper.abort();
            if (leftOrRight == 1) {
                viewMain.layout(rectMainLeftOpen.left, rectMainLeftOpen.top, rectMainLeftOpen.right, rectMainLeftOpen.bottom);
                viewOne.layout(rectOneOpen.left, rectOneOpen.top, rectOneOpen.right, rectOneOpen.bottom);
            } else if (leftOrRight == 2) {
                viewMain.layout(rectMainRightOpen.left, rectMainRightOpen.top, rectMainRightOpen.right, rectMainRightOpen.bottom);
                viewTwo.layout(rectTwoOpen.left, rectTwoOpen.top, rectTwoOpen.right, rectTwoOpen.bottom);
            } else {
                viewMain.layout(rectMainClose.left, rectMainClose.top, rectMainClose.right, rectMainClose.bottom);
                viewOne.layout(rectOneClose.left, rectOneClose.top, rectOneClose.right, rectOneClose.bottom);
                viewTwo.layout(rectTwoClose.left, rectTwoClose.top, rectTwoClose.right, rectTwoClose.bottom);
            }
        }
        ViewCompat.postInvalidateOnAnimation(this);
    }

    private void close(boolean animation) {
        isOpen = false;
        if (animation) {
            mViewDragHelper.smoothSlideViewTo(viewMain, rectMainClose.left, rectMainClose.top);
        } else {
            mViewDragHelper.abort();
            viewMain.layout(rectMainClose.left, rectMainClose.top, rectMainClose.right, rectMainClose.bottom);
            viewOne.layout(rectOneClose.left, rectOneClose.top, rectOneClose.right, rectOneClose.bottom);
            viewTwo.layout(rectTwoClose.left, rectTwoClose.top, rectTwoClose.right, rectTwoClose.bottom);
        }
        ViewCompat.postInvalidateOnAnimation(this);
    }

    public boolean isOpen() {
        return isOpen;
    }

    @Override
    public void computeScroll() {
        if (mViewDragHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }
}
